home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 333_01 / awk2.c < prev    next >
C/C++ Source or Header  |  1989-04-21  |  33KB  |  1,232 lines

  1. /*
  2.  * awk2 --- gawk parse tree interpreter
  3.  *
  4.  * Copyright (C) 1986 Free Software Foundation
  5.  *   Written by Paul Rubin, August 1986
  6.  *
  7.  */
  8.  
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <math.h>
  14. #include <setjmp.h>
  15. #include "awk.h"
  16.  
  17.  
  18. /* More of that debugging stuff */
  19. #ifdef FAST
  20. #define DEBUG(X)
  21. #else
  22. #define DEBUG(X)         print_debug X
  23. #endif
  24.  
  25. /* longjmp return codes, must be nonzero */
  26. /* Continue means either for loop/while continue, or next input record */
  27. #define TAG_CONTINUE 1
  28. /* Break means either for/while break, or stop reading input */
  29. #define TAG_BREAK 2
  30.  
  31. /* the loop_tag_valid variable allows continue/break-out-of-context
  32.  * to be caught and diagnosed (jfw) */
  33.  
  34. #define PUSH_BINDING(stack, x)            \
  35.             (memcpy((stack), (x), sizeof(jmp_buf)), loop_tag_valid++)
  36.  
  37. #define RESTORE_BINDING(stack, x)        \
  38.             (memcpy((x), (stack), sizeof(jmp_buf)), loop_tag_valid--)
  39.  
  40. /* for "for(iggy in foo) {" */
  41. struct search
  42. {
  43.     int             numleft;
  44.     AHASH         **arr_ptr;
  45.     AHASH          *bucket;
  46.     NODE           *symbol;
  47.     NODE           *retval;
  48. };
  49.  
  50. STATIC struct search *    NEAR PASCAL    assoc_scan(NODE *symbol);
  51. STATIC struct search *    NEAR PASCAL    assoc_next(struct search *lookat);
  52.  
  53.  
  54. /* Tree is a bunch of rules to run.
  55.    Returns zero if it hit an exit() statement */
  56.  
  57. int PASCAL interpret(NODE *tree)
  58. {
  59.     register NODE  *t;             /* temporary */
  60.  
  61.     auto jmp_buf    loop_tag_stack;  /* shallow binding stack for loop_tag */
  62.     static jmp_buf  loop_tag;         /* always the current binding */
  63.     static int      loop_tag_valid = 0;    /* nonzero when loop_tag valid (jfw) */
  64.  
  65.     static jmp_buf  rule_tag;    /* tag the rule currently being run, for NEXT
  66.                  * and EXIT statements.  It is static because
  67.                  * there are no nested rules */
  68.  
  69.     register NODE **lhs;    /* lhs == Left Hand Side for assigns, etc */
  70.     register struct search *l;    /* For array_for */
  71.  
  72.     /* clean up temporary strings created by evaluating expressions in
  73.      * previous recursive calls */
  74.     obstack_free(&temp_strings, ob_dummy);
  75.  
  76.     if (tree == NULL)
  77.     return(1);
  78.     switch (tree->type)
  79.     {
  80. #ifndef FAST
  81.         /* Can't run these! */
  82.     case NODE_ILLEGAL:
  83.     case NODE_RULE_NODE:
  84.     case NODE_IF_BRANCHES:
  85.     case NODE_EXPRESSION_LIST:
  86.     case NODE_K_BEGIN:
  87.     case NODE_K_END:
  88.     case NODE_REDIRECT_OUTPUT:
  89.     case NODE_REDIRECT_APPEND:
  90.     case NODE_REDIRECT_PIPE:
  91.     case NODE_VAR_ARRAY:
  92.     case NODE_CONDEXP_BRANCHES:
  93.         panic("Illegal node type (%d) in interpret()", tree->type);
  94. #endif
  95.     case NODE_RULE_LIST:
  96.         for (t = tree; t != NULL; t = t->rnode)
  97.         {
  98.         switch (setjmp(rule_tag))
  99.         {
  100.             case 0:    /* normal non-jump */
  101.             if (eval_condition(t->lnode->lnode))
  102.             {
  103.                 DEBUG(("Found a rule:%p", (FPTR)t->lnode->rnode));
  104.                 if (t->lnode->rnode == NULL)
  105.                 {
  106.                 /* special case: pattern with no action is
  107.                  * equivalent to an action of {print} (jfw) */
  108.                 NODE            printnode;
  109.  
  110.                 printnode.type = NODE_K_PRINT;
  111.                 printnode.lnode = NULL;
  112.                 printnode.rnode = NULL;
  113.                 hack_print_node(&printnode);
  114.                 }
  115.                 else
  116.                 (void) interpret(t->lnode->rnode);
  117.             }
  118.             break;
  119.             case TAG_CONTINUE:    /* NEXT statement */
  120.             return(1);
  121.             case TAG_BREAK:
  122.             return(0);
  123.         }
  124.         }
  125.         break;
  126.     case NODE_STATEMENT_LIST:
  127.         /* print_a_node(tree); */
  128.         /* because BEGIN and END do not have Node_rule_list nature, yet
  129.          * can have exits and nexts, we special-case a setjmp of rule_tag
  130.          * here. (jfw) */
  131.         if (tree == begin_block || tree == end_block)
  132.         {
  133.         switch (setjmp(rule_tag))
  134.         {
  135.             case TAG_CONTINUE:    /* next */
  136.             panic("unexpected next");
  137.             return(1);
  138.             case TAG_BREAK:
  139.             return(0);
  140.         }
  141.         }
  142.         for (t = tree; t != NULL; t = t->rnode)
  143.         {
  144.         DEBUG(("Statements:%p", (FPTR) t->lnode));
  145.         (void) interpret(t->lnode);
  146.         }
  147.         break;
  148.     case NODE_K_IF:
  149.         DEBUG(("IF:%p", (FPTR) tree->lnode));
  150.         if (eval_condition(tree->lnode))
  151.         {
  152.         DEBUG(("True:%p", (FPTR) tree->rnode->lnode));
  153.         (void) interpret(tree->rnode->lnode);
  154.         }
  155.         else
  156.         {
  157.         DEBUG(("False:%p", (FPTR) tree->rnode->rnode));
  158.         (void) interpret(tree->rnode->rnode);
  159.         }
  160.         break;
  161.     case NODE_K_WHILE:
  162.         PUSH_BINDING(loop_tag_stack, loop_tag);
  163.  
  164.         DEBUG(("WHILE:%p", (FPTR) tree->lnode));
  165.         while (eval_condition(tree->lnode))
  166.         {
  167.         switch (setjmp(loop_tag))
  168.         {
  169.             case 0:    /* normal non-jump */
  170.             DEBUG(("DO:%p", (FPTR) tree->rnode));
  171.             (void) interpret(tree->rnode);
  172.             break;
  173.             case TAG_CONTINUE:    /* continue statement */
  174.             break;
  175.             case TAG_BREAK:    /* break statement */
  176.             RESTORE_BINDING(loop_tag_stack, loop_tag);
  177.             return(1);
  178. #ifndef FAST
  179.             default:
  180.             panic("Bad setjmp return (WHILE) - interpret()");
  181. #endif
  182.         }
  183.         }
  184.         RESTORE_BINDING(loop_tag_stack, loop_tag);
  185.         break;
  186.     case NODE_K_FOR:
  187.         PUSH_BINDING(loop_tag_stack, loop_tag);
  188.         DEBUG(("FOR:%p", (FPTR) tree->forloop->init));
  189.         (void) interpret(tree->forloop->init);
  190.         DEBUG(("FOR.WHILE:%p", (FPTR) tree->forloop->cond));
  191.         while (eval_condition(tree->forloop->cond))
  192.         {
  193.         switch (setjmp(loop_tag))
  194.         {
  195.             case 0:    /* normal non-jump */
  196.             DEBUG(("FOR.DO:%p", (FPTR) tree->lnode));
  197.             (void) interpret(tree->lnode);
  198.             /* fall through */
  199.             case TAG_CONTINUE:    /* continue statement */
  200.             DEBUG(("FOR.INCR:%p", (FPTR)tree->forloop->incr));
  201.             (void) interpret(tree->forloop->incr);
  202.             break;
  203.             case TAG_BREAK:    /* break statement */
  204.             RESTORE_BINDING(loop_tag_stack, loop_tag);
  205.             return(1);
  206. #ifndef FAST
  207.             default:
  208.             panic("Bad setjmp return (FOR.WHILE) - interpret()");
  209. #endif
  210.         }
  211.         }
  212.         RESTORE_BINDING(loop_tag_stack, loop_tag);
  213.         break;
  214.     case NODE_K_ARRAYFOR:
  215.         PUSH_BINDING(loop_tag_stack, loop_tag);
  216.         DEBUG(("AFOR.VAR:%p", (FPTR) tree->forloop->init));
  217.         lhs = get_lhs(tree->forloop->init);
  218.         do_deref();
  219.         for (l = assoc_scan(tree->forloop->incr); l; l = assoc_next(l))
  220.         {
  221.         *lhs = dupnode(l->retval);
  222.         DEBUG(("AFOR.NEXTIS:%p", (FPTR) *lhs));
  223.         switch (setjmp(loop_tag))
  224.         {
  225.             case 0:
  226.             DEBUG(("AFOR.DO:%p", (FPTR) tree->lnode));
  227.             (void) interpret(tree->lnode);
  228.             case TAG_CONTINUE:
  229.             break;
  230.  
  231.             case TAG_BREAK:
  232.             RESTORE_BINDING(loop_tag_stack, loop_tag);
  233.             return(1);
  234. #ifndef FAST
  235.             default:
  236.             panic("Bad setjmp return (AFOR.NEXT) - interpret()");
  237. #endif
  238.         }
  239.         }
  240.         RESTORE_BINDING(loop_tag_stack, loop_tag);
  241.         break;
  242.     case NODE_K_BREAK:
  243.         DEBUG(("BREAK:"));
  244.         if (loop_tag_valid == 0)    /* jfw */
  245.         panic("unexpected break or continue");
  246.         longjmp(loop_tag, TAG_BREAK);
  247.         break;
  248.     case NODE_K_CONTINUE:
  249.         DEBUG(("CONTINUE:"));
  250.         if (loop_tag_valid == 0)    /* jfw */
  251.         panic("unexpected break or continue");
  252.         longjmp(loop_tag, TAG_CONTINUE);
  253.         break;
  254.     case NODE_K_PRINT:
  255.         DEBUG(("PRINT:%p", (FPTR) tree));
  256.         (void) hack_print_node(tree);
  257.         break;
  258.     case NODE_K_PRINTF:
  259.         DEBUG(("PRINTF:%p", (FPTR) tree));
  260.         (void) do_printf(tree);
  261.         break;
  262.     case NODE_K_NEXT:
  263.         DEBUG(("NEXT:"));
  264.         longjmp(rule_tag, TAG_CONTINUE);
  265.         break;
  266.     case NODE_K_EXIT:
  267.         /* The unix awk doc says to skip the rest of the input.  Does
  268.          * that mean after performing all the rules on the current line?
  269.          * Unix awk quits immediately, so this does too. */
  270.         /* The UN*X exit can also take an optional arg return code.  We
  271.          * don't */
  272.         /* Well, we parse it, but never *DO* it */
  273.         DEBUG(("EXIT:"));
  274.         longjmp(rule_tag, TAG_BREAK);
  275.         break;
  276.     case NODE_K_DELETE:
  277.         assoc_lookup(tree->lnode, tree->rnode, ASSOC_DELETE);
  278.         break;
  279.     default:
  280.         /* Appears to be an expression statement.  Throw away the value. */
  281.         DEBUG(("Exp:"));
  282.         (void) tree_eval(tree);
  283.         break;
  284.     }
  285.     return(1);
  286. }
  287.  
  288.  
  289. /* evaluate a subtree, allocating strings on a temporary stack. */
  290. /* This used to return a whole NODE, instead of a ptr to one, but that
  291.    led to lots of obnoxious copying.